<!DOCTYPE html>
<html>
  <head>
	<title>app:URI compliance tests</title>
	<script src='resources/testharness.js'></script>
	<script src='resources/testharnessreport.js'></script>
	<link rel='stylesheet' href='resource/testharness.css'>
	<link rel="help" href="http://app-uri.sysapps.org/" data-tested-assertations="following::OL[1]/LI[2]" />
	<style>
		div {padding:5px 5px 10px 5px;}
	</style>
  </head>
  <body>
	<div id="logs"></div> 
	<div id="log"></div>


  <script>
    /**********************************************************************************************
     * This test suite checks your implementation for compliance with the app-URI specification	  *
     **********************************************************************************************/

    /* Check if protocol is "app" */
    if (window.location.protocol === "app:") {

         /* Logging current domain */
        var domain = window.location.protocol + "//" + window.location.host + "/";
        document.getElementById("logs").innerHTML = "Current domain: " + domain;
        
	/* Function that will change HOST value if it is equal to currect application host */
	function ChangeHostIfEqCurrent(URI){
		/* Check if URI host is NOT the same as current application host */
		if (URI.substring(6, 35) === window.location.host) {
		    if (URI.substring(6, 7) !== 4)
			URI = URI.replace(URI.substring(6, 7), "4");
		    else
			URI = URI.replace(URI.substring(6, 7), "5");
		}
		return URI;
	}

        /********************************************************
         *	6.1 Synthesizing an app: URI 
         *	
         *	link: http://app-uri.sysapps.org/#synthesizing
         *	
         ********************************************************/

        /**
         *	Syntax-Based Normalization
         *
         *	rules for dereferencing an app: URI => 3. Let URI be the value of the [HTTP] Request URI.
         */

        var TC_name = "Test: Synthesizing an app:URI. Syntax-Based Normalization";

	// variable needed to test scheme-based normalization 
        var tmp_domain = window.location.protocol + "//" + window.location.host; 

        var CaseNormalizationXHRtests = [ /* scheme: [ TC name, URI] */
            [TC_name + " XHR full path: {} => %7b%7d", 
            domain + 'resources/ExamPLE/%7bmY%7d/z...z/index.html'],
            [TC_name + " XHR full path: } => %7D", 
            domain + 'resources/ExamPLE/%7bmY%7D/z...z/index.html'],
            [TC_name + " XHR full path: {} => %7B%7D", 
            domain + 'resources/ExamPLE/%7BmY%7D/z...z/index.html'],
            [TC_name + " XHR full path: Capital letters in patch", 
            domain + 'resources/ExamPLE/mmY/index.html'],
            [TC_name + " XHR relative path: {} => %7b%7d", 
            'resources/ExamPLE/%7bmY%7d/z...z/index.html'],
            [TC_name + " XHR relative path: } => %7D", 
            'resources/ExamPLE/%7bmY%7D/z...z/index.html'],
            [TC_name + " XHR relative path: P. => %50%2e", 
            'resources/Exam%50LE/%7bmY%7d/z%2e..z/index.html'],
            [TC_name + " XHR relative path: Capital letters in patch", 
            'resources/ExamPLE/mmY/index.html'],
            [TC_name + " XHR relative path: ~ => ~", 
            'resources/ImaGes/~t/{!a}/~sth.png'],
            [TC_name + " XHR relative path: ~{} => ~%7b%7d", 
            'resources/ImaGes/~t/%7b!a%7d/~sth.png'],
            
            /*  Percent-Encoding Normalization*/
            [TC_name + " Percent-Encoding Normalization - XHR full path: c. => %63%2e", 
            domain + 'resources/ExamPLE/%7bmY%7d/z%2e..z/index.html'],
            [TC_name + " Percent-Encoding Normalization - XHR full path: P. => %50%2e", 
            domain + 'resources/Exam%50LE/%7bmY%7d/z%2e..z/index.html'],
            [TC_name + " Percent-Encoding Normalization - XHR relative path: {} => %7B%7D", 
            'resources/ExamPLE/%7BmY%7D/z...z/index.html'],
            [TC_name + " Percent-Encoding Normalization - XHR relative path: c. => %63%2e", 
            'resources/ExamPLE/%7bmY%7d/z%2e..z/index.html'],
            [TC_name + " XHR relative path: ~{} => ~%7b%7d", 
            'resources/ImaGes/~t/%7b!a%7d/~sth.png'],
            
            /*  Path Segment Normalization */
            [TC_name + " Path Segment Normalization: using '../..' in path ", 
            'resources/ExamPLE/mmY/../../ImaGes/~t/%7b!a%7d/~sth.png'],
            
            /*  Scheme-Based Normalization */
            [TC_name + " Scheme-Based Normalization: domain:/", 
            tmp_domain + ':/resources/ImaGes/~t/%7b!a%7d/~sth.png']
        ];

        CaseNormalizationXHRtests.forEach(function (data, i) {
            var name = data[0];
            var URI = data[1];
            var xhrTest = async_test(name + " [case " + i + "]");
            var xhr;
            xhrTest.step(function () {
                xhr = new XMLHttpRequest();
                xhr.open("GET", URI, true);
                xhr.onreadystatechange = xhrTest.step_func(function (ev) {
                    if (xhr.readyState === 4 && xhr.status === 200) {
                        assert_true(true);
                        xhrTest.done();
                    }
                    if (xhr.readyState !== 4 && xhr.status !== 200 && xhr.status !== 0) {
                        assert_true(false, 
                        "[ Error: readyState=" + xhr.readyState + " satus=" + xhr.status + "] ");
                    }
                });
                xhr.send();
            });
            delete name, URI, xhr, xhrTest;
        });
        delete CaseNormalizationXHRtests;


        /**
         *	ContentType reponse
         *
         *	rules for dereferencing an app: URI => 
		  8. Let potential-file be the result of attempting locate the file at path
         */

        TC_name = "Test: [HTTP] 200 reponse status (OK),value of content-type as the [HTTP] ";
        TC_name += "Content-Type header, and the contents of potential-file as the response body";

        var ContentTypeResponsetests = [ /* scheme:[ TC name, URI, content-type] */
            [TC_name + ' [text/html]', 'resources/ExamPLE/mmY/index.html', 'text/html'],
            [TC_name + " [image/png]", 'resources/ImaGes/~t/%7b!a%7d/~sth.png', "image/png"],
            [TC_name + " [text/plain]", 'resources/ExamPLE/mmY/sth.txt', "text/plain"]
        ];

        ContentTypeResponsetests.forEach(function (data, i) {
            var name = data[0];
            var URI = data[1];
            var content_type = data[2];
            var xhrTest = async_test(name + " [case " + i + "]");
            var xhr;
            xhrTest.step(function () {
                xhr = new XMLHttpRequest();
                xhr.open("GET", URI, true);
                xhr.onreadystatechange = xhrTest.step_func(function (ev) {
                    if (xhr.readyState === 4 && xhr.status === 200) {
                        assert_true(xhr.getResponseHeader("Content-Type") === content_type, 
                        "[Content-Type does not mach with expected, it is: " 
                        + xhr.getResponseHeader("Content-Type") + "]");
                        
                        xhrTest.done();
                    }
                    if (xhr.readyState !== 4 && xhr.status !== 200 && xhr.status !== 0) {
                        assert_true(false, 
                        "[ Error: readyState=" + xhr.readyState + " satus=" + xhr.status + "] ");
                    }
                });
                xhr.send();
            });
            delete name, URI, xhr, xhrTest, content_type;
        });
        delete ContentTypeResponsetests;


        /**	
         *	Case Normalization in Path
         *
         *	rules for dereferencing an app: URI => 
		  4. Resolve URI into an absolute URL using the document's origin as the base.
         *	rules for dereferencing an app: URI => 7. Let path be the path component of URI.
         *
         *	Character Normalization in domain name
         */



        TC_name = "Test: Synthesizing an app:URI. Syntax-Based Normalization: Case Normalization";
        var PathCaseNormalizationtests = [ /* scheme: [ TC name, URI] */
            [TC_name, "resources/ImaGes/{{a}}/Test_1/$a/sth34!.png", 
            domain + "resources/ImaGes/%7B%7Ba%7D%7D/Test_1/$a/sth34!.png", true],
            [TC_name, "resources/ImaGes/{{a}}/Test_1/$a/sth34!.png", 
            domain + "resources/ImaGes/%7b%7Ba%7D%7D/Test_1/$a/sth34!.png", false],
            
            /* 	Character Normalization in Domain	*/
            [TC_name, window.location.protocol + "//" + window.location.host.toUpperCase() 
            + "/resources/ImaGes/{{a}}/Test_1/$a/sth34!.png", 
            domain + "resources/ImaGes/%7B%7Ba%7D%7D/Test_1/$a/sth34!.png", true]
        ];

        PathCaseNormalizationtests.forEach(function (data, i) {
            var name = data[0];
            var elem_path = data[1];
            var path_expected = data[2];
            var expected = data[3];
            test(function () {
                var img = document.createElement("img");
                img.src = elem_path;
                if (expected)
                    assert_true(img.src === path_expected, 
                    "[Error, path=" + img.src + "   Expected=" + domain + path_expected + "]");
                else
                    assert_false(img.src === path_expected, 
                    "[Error, path=" + img.src + "   Expected=" + domain + path_expected + "]");
                delete img;

            }, name + " [case " + i + "]");
            delete elem_path, path_expected, expected, name;
        });
        delete PathCaseNormalizationtests;




        /********************************************************************************************
         *	6.4 Dereferencing and retrieval of files from a container 
         *	 
         *	link: http://app-uri.sysapps.org/#dereferencing-and-retrieval-of-files-from-a-container 
         *	
         ********************************************************************************************/
         
         
         
        /**	
         *	501 Method Not Implemented error  - response body MUST be empty
         *
         *	rules for dereferencing an app: URI => 
		  1. If the request is not a [HTTP] GET request, 
		     return a [HTTP] 501 Not Implemented response and terminate this algorithm.
         */


        function Get_501_reponse(name, URI, expected_response) {
            var xhrTest = async_test(name);
            xhrTest.step(function () {
                var xhr = new XMLHttpRequest();
                /* on purpose wrong method "gett" instead of "get" was used */
                xhr.open("gett", URI, true);
                xhr.onreadystatechange = xhrTest.step_func(function (ev) {
                    if (xhr.readyState !== 4 && xhr.status === 501) {
                        assert_true(xhr.response === expected_response, 
                        "[" + xhr.status + " error, response:[" + xhr.response + "] " + "]");
                        
                        xhrTest.done();
                    }
                    if (xhr.readyState === 4 && xhr.status === 200) {
                        assert_true(false, 
                        "[Should get 501 but got 200 OK, "
                        +"file found while it should not find it, "
                        +"	non existing 'gett' method used");
                    }
                });
                xhr.send();
            });
            delete xhrTest;
        }
        Get_501_reponse(TC_name + " 501 Method Not Implemented error expected", 
        'resources/ExamPLE/mmY/index.html', "");

        
        /**	
         *	400 Bad Request error - response body MUST be empty
         *
         *	rules for dereferencing an app: URI => 
		  5. If the URI does not conform to the appuri ABNF, return a 
		      [HTTP] 400 Bad Request response and terminate this algorithm. 
         */

        function Get_400_reponse(name, URI, expected_response) {
            var xhrTest = async_test(name);
            xhrTest.step(function () {
                var xhr = new XMLHttpRequest();
		//alert(URI);
                xhr.open("GET", URI, true);
                xhr.onreadystatechange = xhrTest.step_func(function (ev) {
                    if (xhr.readyState !== 4 && xhr.status === 400) {
                        assert_true(xhr.response === expected_response, 
                        "[" + xhr.status + " error, response:[" + xhr.response + "] " + "]");
                        
                        xhrTest.done();
                    }
                    if (xhr.readyState === 4 && xhr.status === 200) {
                        assert_true(false, 
                        "[Should get 400 but got 200 OK, "
                        +"file found while it should not find it, "
                        +"since no specific file requested]");
                    }
                });
                xhr.send();
            });
            delete xhrTest;
        }
        Get_400_reponse(TC_name + " 400 Method Not Implemented error expected, no path", 
        tmp_domain, "");
	Get_400_reponse(TC_name + " 400 Method Not Implemented error expected, different domain with no path", 
        ChangeHostIfEqCurrent("app://f15a6d20-cefa-13e5-1972-800e20d19a76"), "");


	/**	
         *	403 Forbidden error - response body MUST be empty
         *
         *	rules for dereferencing an app: URI => 
		  6. If the URI uses the scheme 'app', but the authority does not match
		     the one assigned to this document, return a [HTTP] 403 Forbidden 
		     response and terminate this algorithm 
		     (i.e., prevent inter-application content access).
         */

        function Get_403_reponse(name, URI, expected_response) {
            var xhrTest = async_test(name);
            xhrTest.step(function () {
                /* Change if URI host is the same as current application host */
                URI = ChangeHostIfEqCurrent(URI);
                var xhr = new XMLHttpRequest();
                xhr.open("GET", URI, true);
                xhr.onreadystatechange = xhrTest.step_func(function (ev) {
                    if (xhr.readyState === 4 && xhr.status === 200) {
                        assert_true(false, "[403 error expected, got: 200 OK instead]");
                    }
                    if (xhr.readyState !== 4 && xhr.status === 403) {
                        assert_true(xhr.response === expected_response, "[" 
                        + xhr.status + " error, response:[" + xhr.response + "] " 
                        + "]");
                        xhrTest.done();
                    }
                });
                xhr.send();
            });
        }
        Get_403_reponse(TC_name + " Access to resticted URI - 403 Forbidden error expected", 
        window.location.protocol + "//f15a6d20-cefa-13e5-1972-800e20d19a76/" + 'resources/ExamPLE/mmY/index.html', "");


        /**	
         *	404 Not Found error - response body MUST be empty
         *
         *	rules for dereferencing an app: URI => 
		  9. If potential-file is not found at the given path inside the container, 
		     return a [HTTP] 404 Not Found response.
         */

        TC_name = "Test: 6.4 Dereferencing and retrieval of files from a container";

        var CompareResponseBodytests = [ /* scheme: [TC name, URI, expected_response]*/
            [TC_name + " 404 Not Found error expected", 
            'resources/ImaGes/~t/%7b!a%7d/~sth11.png', ""]
        ];

        CompareResponseBodytests.forEach(function (data, i) {
            var name = data[0];
            var URI = data[1];
            var expected_response = data[2];
            var xhrTest = async_test(name);
            var xhr;
            xhrTest.step(function () {
                xhr = new XMLHttpRequest();
                xhr.open("GET", URI, true);
                xhr.onreadystatechange = xhrTest.step_func(function (ev) {
                    if (xhr.readyState !== 4 && xhr.status === 404) {
                        assert_true(xhr.response === expected_response, 
                        "[" + xhr.status + " error, response:[" + xhr.response + "] " + "]");
                        xhrTest.done();
                    }
                    if (xhr.readyState === 4 && xhr.status === 200) {
                        assert_true(false, "[404 error expected, got: 200 OK instead]");
                    }
                });
                xhr.send();
            });
            delete xhrTest, xhr;
        });
        delete CompareResponseBodytests;



    } else {
        document.getElementById("logs").innerHTML = 
        "This is a test suite for app protocol only. Test aborted due to current protocol " 
        + window.location.protocol;
    }
    
  </script>
  </body>
</html>



